
/**	
*	
	Doyle Spiral
*/

import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;

import java.awt.Color;
import java.awt.Polygon;
import java.util.ArrayList;
import java.util.Random; 


import pluginUtils.DoyleCircle;


public class doyle1_ extends ImagePlus implements PlugIn {
	private ImageProcessor primeIP; 
	private int X=2000,Y=2000;
	private Random generator=new Random(); 
	private boolean first=true; 
	
	private void drawCircle(DoyleCircle c){
		int intX=(int)(c.getXcenter()*X);
		int intY=(int)(c.getYcenter()*Y);
		int intR=(int)(c.getRadius()*X); // X ??
		primeIP.drawOval(intX-intR,intY-intR,intR*2,intR*2);
		if(first){
		primeIP.fillOval(intX-5,intY-5,10,10);
		first=false;
		}
		
	}
	
	static private boolean tracable(DoyleCircle c){
		if(c.getXcenter()-c.getRadius()>1) return false; 
		if(c.getXcenter()+c.getRadius()<0)return false; 
		if(c.getYcenter()-c.getRadius()>1) return false; 
		if(c.getYcenter()+c.getRadius()<0)return false; 
		return true; 
	}
	
	public void run(String arg) {
		primeIP = new ColorProcessor(X,Y);
		DoyleCircle.setBounds(0,0);
		double a=2.0; 
		double  n=3.0; 
		double  m=2.0; 
		//double blog=(n+0.0)/m*Math.log(a); 
		//double b=Math.exp(blog); 
		double b=Math.pow(a,(n+0.0)/m);
		System.out.println(a+" "+b);
		
		// Calcul des angles
		double u[]={1+1/a+b/a,1+1/a+1/b,1+1/b+a/b,1+a+a/b,1+a+b,1+b+b/a};//1+a+a*b en 5eme pos
		double theta[]={Math.acos((u[0]-b/(a*a))/(u[0]+b/(a*a))),
						Math.acos((u[1]-1/(a*b))/(u[1]+1/(a*b))),
						Math.acos((u[2]-a/(b*b))/(u[2]+a/(b*b))),
						Math.acos((u[3]-a*a/b)/(u[3]+a*a/b)),
						Math.acos((u[4]-a*b)/(u[4]+a*b)),
						Math.acos((u[5]-b*b/a)/(u[5]+b*b/a))
		};
		
		// debug-test : calcul d'un angle de rotation
		// Rotation pour le premier sous-cercle
		double uprov=u[5]*b/a; 
		double alpha=Math.acos((uprov-b)/(uprov+b)); 
		System.out.println("alpha "+alpha*180/Math.PI); 
		double rotat=alpha-Math.PI+theta[4]+theta[5]; 
		System.out.println("rotation "+rotat*180/Math.PI);
		
		// deuxieme cercle 
		double uprov2=u[0]*b/a; 
		double gamma=Math.acos((uprov2-1/a)/(uprov2+1/a));
		double rotat2=theta[5]-gamma; 
		System.out.println("gamma :"+gamma*180/Math.PI+" rotat2 "+rotat2*180/Math.PI); 
		
		double radiusCoef[]={b/a,1.0/a,1.0/b,a/b,a,b};
		
		
		double rotationAngle[]=new double[6]; 
		rotationAngle[0]=rotat; 
		rotationAngle[1]=rotat2;
		rotationAngle[2]=-Math.PI+(theta[0]+theta[1]+theta[5]);
		rotationAngle[3]=-Math.PI+(theta[0]+theta[1]+theta[2]); 
		
		
		// cinquieme cercle
		double uprov5=u[4]*a;
		double delta=Math.acos((uprov5-b)/(uprov5+b));
		double beta=Math.PI-(theta[4]+theta[5]); 
		rotationAngle[4]=beta-delta; 
		
		// sixieme cercle
		double uprov6=u[5]*b;
		double eta=Math.acos((uprov6-b/a)/(uprov6+b/a));
		rotationAngle[5]=Math.PI-theta[5]-eta-theta[0];  
		
		Polygon background=new Polygon(new int[]{0,0,X,Y},new int[]{0,X,Y,0},4);
		primeIP.setColor(new Color(0.9f,0.9f,0.82f));
		
		primeIP.fillPolygon(background);
		
		ArrayList<DoyleCircle> todo=new ArrayList<DoyleCircle>();
		ArrayList<DoyleCircle> traces=new ArrayList<DoyleCircle>(); 
		primeIP.setColor(new Color(0.9f,0.0f,0.82f));
		
		/*******************************************************/
		DoyleCircle init=new DoyleCircle(0.5,0.5,0.75,0.05,0,0); 
		todo.add(init); 
		System.out.println("Added :"+init); 
		int iter=0; 
		boolean firstTime=true; 
		while((!todo.isEmpty())&&(iter<1000)){
			//int choice=generator.nextInt(todo.size());
			int choice=0;
			DoyleCircle current=todo.get(choice);
			todo.remove(choice); 
			if(!traces.contains(current)){
					traces.add(current); 
					iter++; 
					if(iter%1000==0)System.out.println(iter); 
					
					drawCircle(current); 
					
					
					double theta0=current.getRotation(); 
					int adding=0; 
					for(int i=0;i<6;i++){
						double rad=current.getRadius()*(1+radiusCoef[i]); 
						double nX=current.getXcenter()+rad*Math.cos(theta0);
						double nY=current.getYcenter()+rad*Math.sin(theta0);
						double angle=current.getRotation()+rotationAngle[i]; 
						if(angle>2*Math.PI)angle=angle-2*Math.PI; 
						if(angle<-2*Math.PI)angle=angle+2*Math.PI; 
						DoyleCircle c=new DoyleCircle(nX,nY,angle,current.getRadius()*radiusCoef[i],0,0);
						
						if(tracable(c)&&(!todo.contains(c))&&(!traces.contains(c))&&(rad>0.001)){
							todo.add(c); //adding++; 
							if(c.equals(init)) System.out.println("equality"); 
							//System.out.println("Added :"+c); 
							if(todo.size()%100==0)System.out.println("---->"+todo.size());
						}
						 
						
						theta0+=theta[i];
					}// for
					
					
			}// if not trace
		}// while toto not empty
		
	
		
		setProcessor("Verifying", primeIP);
		show();
	}	
	
	
	
	
	
	
	
	
	
	
}